module fifo_async #(parameter DATA_WIDTH = 16, ADDR_WIDTH = 4)
(
	input reset_n,

	input wr_clk,
	input wr_en,
	input [DATA_WIDTH - 1 : 0] wr_data,
	output full,

	input rd_clk,
	input rd_en,
	output [DATA_WIDTH - 1 : 0] rd_data,
	output empty
);

wire [ADDR_WIDTH - 1 : 0] rd_ptr;
wire [ADDR_WIDTH - 1 : 0] rd_ptr_gray;
wire [ADDR_WIDTH - 1 : 0] rd_ptr_gray_sync;
wire [ADDR_WIDTH - 1 : 0] wr_ptr;
wire [ADDR_WIDTH - 1 : 0] wr_ptr_gray;
wire [ADDR_WIDTH - 1 : 0] wr_ptr_gray_sync;

dp_ram #(DATA_WIDTH, ADDR_WIDTH)
dp_ram (
	.wr_clk(wr_clk),
	.wr_en(wr_en),
	.wr_addr(wr_ptr),
	.wr_data(wr_data),
	.rd_clk(rd_clk),
	.rd_addr(rd_ptr),
	.rd_data(rd_data)
);

gen_wr_ptr #(ADDR_WIDTH)
gen_wr_ptr (
	.reset_n(reset_n),
	.wr_clk(wr_clk),
	.wr_en(wr_en),
	.rd_ptr_gray_sync(rd_ptr_gray_sync),
	.wr_ptr_bin(wr_ptr),
	.wr_ptr_gray(wr_ptr_gray),
	.full(full)
);

gen_rd_ptr #(ADDR_WIDTH)
gen_rd_ptr (
	.reset_n(reset_n),
	.rd_clk(rd_clk),
	.rd_en(rd_en),
	.wr_ptr_gray_sync(wr_ptr_gray_sync),
	.rd_ptr_bin(rd_ptr),
	.rd_ptr_gray(rd_ptr_gray),
	.empty(empty)
);

sync #(ADDR_WIDTH)
sync_wr_ptr (
	.reset_n(reset_n),
	.clk(rd_clk),
	.in(wr_ptr_gray),
	.out(wr_ptr_gray_sync)
);

sync #(ADDR_WIDTH)
sync_rd_ptr (
	.reset_n(reset_n),
	.clk(wr_clk),
	.in(rd_ptr_gray),
	.out(rd_ptr_gray_sync)
);

endmodule